﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System.Data.SqlClient;
using System.Linq.Expressions;
using Zhaoxi.ReadingPlatform.BusinessInterface;

namespace Zhaoxi.ReadingPlatform.BusinessService
{
    public class BaseService : IBaseService
    {

        protected DbContext? Context { get; set; }

        public BaseService(DbContext? context)
        {
            Context = context;
        }

        /// <summary>
        /// 增删改查，必须要执行这一句才能生效。
        /// </summary>
        public void Commit()
        {
            Context.SaveChanges();
        }

        public void Delete<T>(int Id) where T : class
        {
            T t = Find<T>(Id);
            if (t == null) throw new Exception("t is null");
            Context.Set<T>().Remove(t);
            Commit();
        }

        public void Delete<T>(T t) where T : class
        {
            if (t == null) throw new ArgumentNullException(nameof(t));
            Context.Set<T>().Attach(t);
            Context.Set<T>().Remove(t);
            Commit();
        }

        public void Delete<T>(IEnumerable<T> tList) where T : class
        {
            foreach (var t in tList)
            {
                Context.Set<T>().Attach(t);
            }
            Context.Set<T>().RemoveRange(tList);
            Commit();
        }

        public void Excute<T>(string sql, SqlParameter[] parameters) where T : class
        {
            IDbContextTransaction trans = null;
            try
            {
                trans = Context.Database.BeginTransaction();
                trans.Commit();
            }
            catch (Exception)
            {
                if (trans != null) trans.Rollback();
                throw;
            }
        }

        public IQueryable<T> ExcuteQuery<T>(string sql, SqlParameter[] parameters) where T : class
        {
            throw new NotImplementedException();
        }

        public T Find<T>(int id) where T : class => Context.Set<T>().Find(id);

        public T Insert<T>(T t) where T : class
        {
            Context.Set<T>().Add(t);
            Commit();
            return t;
        }

        public IEnumerable<T> Insert<T>(IEnumerable<T> tList) where T : class
        {
            Context.Set<T>().AddRange(tList);
            Commit();
            return tList;
        }

        public IQueryable<T> Query<T>(Expression<Func<T, bool>> funcWhere) where T : class
            => Context.Set<T>().Where(funcWhere);

        public PagingData<T> QueryPage<T, S>(Expression<Func<T, bool>> funcWhere, int pageSize, int pageIndex, Expression<Func<T, S>> funcOrderby, bool isAsc = true) where T : class
        {
            var list = Set<T>();
            if (funcWhere != null)
            {
                list = list.Where(funcWhere);
            }
            if (isAsc)
            {
                list = list.OrderBy(funcOrderby);
            }
            else
            {
                list = list.OrderByDescending(funcOrderby);
            }
            PagingData<T> result = new()
            {
                DataList = list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(),
                PageIndex = pageIndex,
                PageSize = pageSize,
                RecordCount = list.Count()
            };
            return result;
        }

        /// <summary>
        /// 不应该暴露是上端使用者，尽量少用。
        /// 这是什么意思？
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IQueryable<T> Set<T>() where T : class
        {
            return Context.Set<T>();
        }

        /// <summary>
        /// 修改一个实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <exception cref="Exception"></exception>
        public void Update<T>(T t) where T : class
        {
            if (t == null) throw new Exception("t is null");
            // 将数据附加到上下文，支持实体修改和新实体，重置为UnChanged
            // 这是什么意思？
            Context.Set<T>().Attach(t);
            Context.Entry(t).State = EntityState.Modified;
            // 保存，然后重置为UnChanged
            Commit();
        }

        /// <summary>
        /// 修改一个集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tList"></param>
        public void Update<T>(IEnumerable<T> tList) where T : class
        {
            foreach (var t in tList)
            {
                Context.Set<T>().Attach(t);
                Context.Entry(t).State = EntityState.Modified;
            }
            Commit();
        }
    }
}
